use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};

#[derive(Debug, Clone)]
pub struct Struct
{
    pub struct_name: String,     //结构体名字
    pub file_name: String,       //源代码文件名
    pub line: usize,             //源代码行
    pub column: usize,           //源代码列
    pub size: Size,              //结构大小
    pub fields: Vec<Field>,      //全部字段
    pub annotation: Vec<String>, //文档注释
}
#[derive(Debug, Clone)]
pub struct Field
{
    pub field_name: String,      //字段名字
    pub field_type: Type,        //字段类型
    pub annotation: Vec<String>, //文档注释
}
#[derive(Debug, Clone)]
pub enum Type
{
    I8,
    I16,
    I32,
    I64,
    I128,
    U8,
    U16,
    U32,
    U64,
    U128,
    F32,
    F64,
    Bool,
    Char,
    Isize,
    Usize,
    Str,
    String,
    Box(Box<Type>),
    Vec(Box<Type>),
    Array(Box<Type>),
    Struct(String),
    Pointer(Box<Type>),
    Reference(Box<Type>),
    Slice(Box<Type>),
    Tuple(Vec<Type>),
    Unknown,
}
#[derive(Debug, Clone)]
pub enum Size
{
    Fixed(u32),
    Dynamic,
}
impl Struct
{
    pub fn new(input: TokenStream) -> Result<Self, TokenStream>
    {
        //解析源代码信息
        let call_span = Span::call_site();
        //原始代码文本字符串
        let raw_input_str = input.to_string();

        /*
        for v in input.into_iter() {
            match v {
                TokenTree::Group(_) => todo!(),
                TokenTree::Ident(_) => todo!(),
                TokenTree::Punct(_) => todo!(),
                TokenTree::Literal(_) => todo!(),
            }
        }
        */

        //解析为syn::Item类型
        let syn_item_result = syn::parse(input);
        if let Ok(syn_item) = syn_item_result
        {
            if let syn::Item::Struct(syn_struct) = syn_item
            {
                let file = String::from(
                    call_span.source_file().path().file_name().unwrap().to_str().unwrap(),
                );
                //解析字段
                let mut fields = Vec::<Field>::new();
                for syn_field in &syn_struct.fields
                {
                    let f = Field::new(syn_field);
                    match f
                    {
                        Ok(v) => fields.push(v),
                        Err(v) => return Err(v),
                    }
                }

                //所有源代码行
                let mut raw_lines = raw_input_str.lines();
                //解析结构上的文档注释
                let mut annotation: Vec<String> = Vec::new();
                loop
                {
                    let it = raw_lines.next();
                    if let Some(ns) = it
                    {
                        if ns.as_bytes()[0] == b'/'
                        {
                            annotation.push(ns.to_string().split_off(3));
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                //解析字段上的文档注释
                let mut field_annotation: Vec<String> = Vec::new();
                loop
                {
                    let next = raw_lines.next();
                    if let Some(ns) = next
                    {
                        let line = ns.trim();

                        if line.as_bytes()[0] != b'/' && field_annotation.len() > 0
                        {
                            let index = line.find(':');
                            if let Some(i) = index
                            {
                                let s = line.split_at(i).0.trim().to_string();
                                for f in fields.iter_mut()
                                {
                                    if f.field_name == s
                                    {
                                        f.annotation.append(&mut field_annotation);
                                        break;
                                    }
                                }
                            }
                            field_annotation.clear();
                        }

                        let index = line.find("///");
                        if let Some(i) = index
                        {
                            let ss = line.split_at(i + 3);
                            field_annotation.push(ss.1.to_string());
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                //创建返回
                Ok(Struct {
                    size: if fields.len() == 0
                    {
                        Size::Fixed(0)
                    }
                    else
                    {
                        Size::Dynamic
                    },
                    struct_name: syn_struct.ident.to_string(),
                    fields: fields,
                    file_name: file,                  //源代码文件
                    line: call_span.start().line(),     //源代码行
                    column: call_span.start().column(), //源代码列
                    annotation: annotation,           //注释
                })
            }
            else
            {
                Err(compile_error("net_ser宏只能添加给结构体", &call_span))
            }
        }
        else
        {
            Err(compile_error("解析为syn::Item类型失败", &call_span))
        }
    }
}
impl Field
{
    pub fn new(syn_field: &syn::Field) -> Result<Self, TokenStream>
    {
        if let Option::Some(v) = &syn_field.ident
        {
            let t = Type::new(&syn_field.ty);
            if let Type::Unknown = t
            {
                return Err(compile_error("不支持序列化的类型", &v.span().unwrap()));
            }
            Ok(Field {
                field_name: v.to_string(),
                field_type: t,
                annotation: Vec::new(),
            })
        }
        else
        {
            Err(compile_error("不支持匿名类型！", &Span::call_site()))
        }
    }
}
impl Type
{
    pub fn new(syn_type: &syn::Type) -> Self
    {
        let mut parse_type = Type::Unknown;
        match syn_type
        {
            syn::Type::Path(v) => match v.path.segments.first()
            {
                Some(vv) =>
                {
                    let n = vv.ident.to_string();
                    match &vv.arguments
                    {
                        syn::PathArguments::None =>
                        {
                            //直接类型
                            match n.as_str()
                            {
                                "i8" => parse_type = Type::I8,
                                "i16" => parse_type = Type::I16,
                                "i32" => parse_type = Type::I32,
                                "i64" => parse_type = Type::I64,
                                "i128" => parse_type = Type::I128,
                                "u8" => parse_type = Type::U8,
                                "u16" => parse_type = Type::U16,
                                "u32" => parse_type = Type::U32,
                                "u64" => parse_type = Type::U64,
                                "u128" => parse_type = Type::U128,
                                "f32" => parse_type = Type::F32,
                                "f64" => parse_type = Type::F64,
                                "bool" => parse_type = Type::Bool,
                                "char" => parse_type = Type::Char,
                                "isize" => parse_type = Type::Isize,
                                "usize" => parse_type = Type::Usize,
                                "str" => parse_type = Type::Str,
                                "String" => parse_type = Type::String,
                                _ => parse_type = Type::Struct(n.clone()),
                            }
                        }
                        syn::PathArguments::AngleBracketed(aa) =>
                        {
                            //泛型类型
                            match aa.args.first()
                            {
                                Some(vv) => match &vv
                                {
                                    syn::GenericArgument::Type(v) => match n.as_str()
                                    {
                                        "Box" => parse_type = Type::Box(Box::new(Self::new(v))),
                                        "Vec" => parse_type = Type::Vec(Box::new(Self::new(v))),
                                        _ => println!("不支持序列化类型"),
                                    },
                                    _ => println!("不支持序列化类型"),
                                },
                                _ => println!("不支持序列化类型"),
                            };
                        }
                        _ => println!("不支持序列化类型"),
                    };
                }
                _ => println!("不支持序列化类型"),
            },
            syn::Type::Array(v) =>
            {
                parse_type = Type::Array(Box::new(Self::new(v.elem.as_ref())));
            }
            syn::Type::Ptr(_) =>
            {
                // TOD...
                parse_type = Type::Pointer(Box::new(Type::Unknown));
            }
            syn::Type::Reference(_) =>
            {
                // TOD...
                parse_type = Type::Reference(Box::new(Type::Unknown));
            }
            syn::Type::Slice(_) =>
            {
                // TOD...
                parse_type = Type::Slice(Box::new(Type::Unknown));
            }
            syn::Type::Tuple(_) =>
            {
                // TOD...
                parse_type = Type::Tuple(Vec::new());
            }
            _ => println!("不支持序列化的类型"),
        }
        parse_type
    }
}

fn compile_error(string: &str, span: &Span) -> TokenStream
{
    let ts = [
        TokenTree::Ident(Ident::new("compile_error", span.clone())),
        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
        TokenTree::Group(Group::new(
            Delimiter::Brace,
            TokenStream::from_iter([TokenTree::Literal(Literal::string(string))]),
        )),
    ];
    TokenStream::from_iter(ts)
}
